#include <iostream>
#include <vector>
#include <string>
#include <cassert>
#include <cstdio>
#include <pthread.h>
#include <unistd.h>
using namespace std;

// int main() {
//     void* ptr = nullptr;
//     cout << sizeof ptr << endl;
//
//     return 0;
// }

#define THREAD_NUM 10

struct ThreadData {
    ThreadData() = default;

    int number; // 自定义编号
    pthread_t tid; // 会在创建新线程时作为输出型参数，获得线程的id
    char name_buffer[64]; // 名字缓冲区，只属于单独的某个线程而不是多个线程共用，避免多个进程同时刷新缓冲区，导致姓名相互覆盖
};

struct ReturnValue {
    ReturnValue() = default;

    ReturnValue(const int& exit_code, const string& return_message = "")
        : exit_code(exit_code)
        , return_message(return_message)
    {}

    int exit_code;
    string return_message;
};

// 该函数被多个线程(执行流)访问，处于重入状态
// 该函数看似是可重入函数，但严格上来讲因为该函数内访问了外设(stdout), 所以是不可重入函数
void* start_routine(void* args) {
    ThreadData* thread_data = static_cast<ThreadData*>(args);
    int cnt = 10;

    while(cnt) {
        cout << "new thread create success, name: " << thread_data->name_buffer << " number: " << thread_data->number << endl;

        cout << "cnt: " << cnt << "&cnt: " << &cnt << endl;
        --cnt;

        sleep(1);
    }

    // 线程退出有三种方法，一种为在执行函数内return， 一种在执行函数内pthread_exit(void*)，一种在主线程内pthread_cancel(pthread_t)
    // 第一种和第二种可以自定义返回值的内容，第三种要求新线程在被cancel之前已经运行起来了，且结束时系统会默认返回(void*)-1

    ReturnValue* return_value = new ReturnValue(0, "return success!");
    // ReturnValue* return_value = new ReturnValue();
    // return_value->exit_code = 0;

    return (void*)return_value;

    // return (void*)110;
}

int main() {
    vector<ThreadData*> threads(THREAD_NUM ,nullptr); // 线程池

    for (int i = 0; i < THREAD_NUM; ++i) {
        threads[i] = new ThreadData();

        threads[i]->number = i + 1;
        snprintf(threads[i]->name_buffer, sizeof(threads[i]->name_buffer), "%s, %d", "thread", i + 1);

        // 创建新线程
        pthread_create(&threads[i]->tid, nullptr, start_routine, threads[i]);
    }

    sleep(10);

    // 取消一半的线程
    // for (int i = 0; i < threads.size() / 2; ++i) {
    //     pthread_cancel(threads[i]->tid);
    //     cout << "pthread_cancel: " << threads[i]->name_buffer << " success! " << endl;
    // }

    // 等待进程退出
    for (auto& thread : threads) {
        // void* ret = nullptr; // 这里有一个问题，我没有办法将ReturnValue对象指针传回来，对它解引用会发生段错误
        // 破案了，首先呢，static_cast不支持我把(安全的强转)ReturnValue**强转为void**
        // 其次呢，发生段错误的原因是因为线程在被取消后，它的资源就已经被回收了，所以在访问threads[0 - 4]时，访问了已释放空间，导致发生段错误
        // 核心转储确实是一个不错的东西
        ReturnValue* return_value = nullptr;
        int n = pthread_join(thread->tid, (void**)&return_value);
        assert(n == 0);
        (void)n;

        cout << "join: " << thread->name_buffer << " success! " <<"exit_code:" << return_value->exit_code << endl;

        delete return_value; //return_value也是new出来的，需要delete
        delete thread; // 自己new出来的就要自己delete， 如果vector里存的是对象的话，就会调用对象的析构函数，但如果是对象的指针的话，就不会调用
    }

    cout << "main thread exit!" << endl;
    return 0;
}